package apiCode;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Scanner;

import org.tmatesoft.svn.core.ISVNLogEntryHandler;
import org.tmatesoft.svn.core.SVNCommitInfo;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.ISVNOptions;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNCommitClient;
import org.tmatesoft.svn.core.wc.SVNLogClient;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNUpdateClient;
import org.tmatesoft.svn.core.wc.SVNWCClient;
import org.tmatesoft.svn.core.wc.SVNWCUtil;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

public class ResultMediator {
	SVNURL url;
	String localrepo;
	SVNRepository repository;
    ISVNEditor editor = null;
	ISVNAuthenticationManager authManager;
	SVNClientManager myClientManager = SVNClientManager.newInstance();
	Properties properties;
	
	public ResultMediator(){
			System.out.println("New Sink");
	}

	/*
	 * Method to read config.properties and user values to 
	 * connect and log in to the repository
	 */
	public void connectToRepo()  {

		String configFile = "config.properties";        
		InputStream inputStream;
		
		// Read config properties file and load details into properties object.
        Properties properties = new Properties();
        
		try {
			
			inputStream = new FileInputStream(configFile);
			
	        System.out.println("load properties with config");
	        properties.load(inputStream);

		} catch (FileNotFoundException e) {
			System.out.println("** LOGIN ERROR config file not found ** ");
			e.printStackTrace();
		} catch (IOException e) {
			
			System.out.println("** LOGIN ERROR  ** ");

			e.printStackTrace();
		}


        // get the property value
        System.out.println("Assign Properties values");
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");
        String repourl = properties.getProperty("repourl");
        this.localrepo = properties.getProperty("localrepo");
				
		// Repository will be accessed using the WebDav protocol https
		DAVRepositoryFactory.setup();
		

		// Implement the authentication manager interface with username password
		// see http://wiki.svnkit.com/Authentication
		authManager = new BasicAuthenticationManager(username,password);
		System.out.println("Authentication completed");
		
		//Create repository driver to bind to defined repository location
		System.out.println("Repository set");
		try {
			this.url = SVNURL.parseURIEncoded(repourl);
			
			System.out.println("URL "+url);

			repository = SVNRepositoryFactory.create( this.url);
	        
			System.out.println( "Repository Root: " + repository.getRepositoryRoot( true ) );
			System.out.println( "Repository UUID: " + repository.getRepositoryUUID( true ) );

		} catch (SVNException e) {
			e.printStackTrace();
		}				
		
        //Set an auth manager which will provide user credentials
        repository.setAuthenticationManager(authManager);  

	}
	
	@SuppressWarnings("deprecation")
	public void update(){
		
        myClientManager.setAuthenticationManager(authManager);
        
		SVNUpdateClient updateClient = myClientManager.getUpdateClient( );
		updateClient.setIgnoreExternals( false );
		
		File localLoc = new File(localrepo); 

		ISVNOptions options;
		options = myClientManager.getOptions();
		System.out.println(options.toString());
		System.out.println("localLoc = "+localLoc);
		long revision;
		try {
			revision = updateClient.doUpdate(localLoc, SVNRevision.HEAD, true);
	        System.out.println("done rev is"+revision);
		} catch (SVNException e) {
			// 
			e.printStackTrace();
		}
	}		
	
	public void checkOut() throws SVNException{
        
		System.out.println("Entering checkout");
		
		SVNUpdateClient uClient;
        myClientManager.setAuthenticationManager(authManager);
        uClient = myClientManager.getUpdateClient();
        
        System.out.println("Local repo is"+localrepo);
        System.out.println("Creating file");
        File dstPath = new File(localrepo);
        
        System.out.println("Before checkout");
        uClient.doCheckout(url, dstPath, SVNRevision.HEAD, SVNRevision.HEAD,SVNDepth.INFINITY, false);
        System.out.println("After checkout");
	}
	public void getHistory() throws SVNException{
        
		System.out.println("Entering log");
		
		SVNLogClient logClient;
        myClientManager.setAuthenticationManager(authManager);
        logClient = myClientManager.getLogClient();
        
        File dstPath = new File(localrepo);
        System.out.println("path = "+dstPath);

        // Log event handler
        ISVNLogEntryHandler logHandler = new ISVNLogEntryHandler() {
        	// This method will process when doLog() is done
            public void handleLogEntry( SVNLogEntry logEntry ) throws SVNException {
                System.out.println( "Author: " + logEntry.getAuthor() );
                System.out.println( "Date: " + logEntry.getDate() );
                System.out.println( "Message: " + logEntry.getMessage() );
                System.out.println( "Revision: " + logEntry.getRevision() );
            }
        };
        
        System.out.println("before do log");

        logClient.doLog(new File[] {dstPath}, SVNRevision.UNDEFINED,SVNRevision.UNDEFINED,false,true,100,logHandler);
        

        System.out.println("after do log");
        
        System.out.println("log handler");

	}

	
	 //Commit to remote repo
	public void commit() throws SVNException{
		
		System.out.println("Enter commit");
		ISVNOptions options = SVNWCUtil.createDefaultOptions( false );
		
		SVNClientManager clientManager = SVNClientManager.newInstance(options, authManager);
		SVNCommitClient scc = clientManager.getCommitClient();
		SVNProperties sp = new SVNProperties();
		String changelist[] = null;
		File file = new File(localrepo);
		System.out.println("File "+file.getAbsolutePath());
		SVNCommitInfo sci;
		sp.put("head", SVNProperty.REVISION);
		
		// get working copy client
		SVNWCClient wcClient = new SVNWCClient(authManager, null);
		
		// schedule new files for addition to repo
		wcClient.doAdd(file, true, false, false, SVNDepth.INFINITY, false,false, false); 

		sci = scc.doCommit(new File[] {file}, false, "test 20140909",sp, changelist, false, false, SVNDepth.INFINITY);
		
		System.out.println("info "+sci);
	}
	
	/*
	 * Commit changes to new file
	 */

	// Write text to a local location
	public void writeResult(String filename,String eventName,String eventResult) {
			
		System.out.println("Writing to file");
		System.out.println("filename "+filename);
		System.out.println("Writing "+eventName);
		System.out.println("EventResult "+eventResult);
        try 
        {
        	System.out.println("Creating File Object");
        	
        	// put xml ext

        	// Create File object
        	File file = new File(localrepo,filename);
        	System.out.println("File object created "+file.getAbsolutePath());

        	// If it's a new event new file needs to be created
        	boolean isNewFile = file.createNewFile();        	
        	System.out.println("Flag = "+isNewFile);

        	// put event results into a map
        	Map<String,String> eventMap = getEventsMap(eventName,eventResult);
        	
        	// Use the event key to get the value string.
        	String indName = (String) eventMap.get(eventName);
        	eventMap.remove("val");
        	
        	System.out.println("Create docfactory");
			// Obtain a parser that produces DOM object trees from XML documents
        	DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();        	
        	 
        	// Api used to obtain a Document from XML
        	DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        	
        	Document doc;
        	Element rootElement = null;
        	
        	if (isNewFile){
        		//Obtain a new instance of a DOM Document object to build a DOM tree with.
        		doc = docBuilder.newDocument();
    		
        		// Create root element called events
        		rootElement = doc.createElement("events");
    		
        		// Add root element to Document tree
        		doc.appendChild(rootElement);
        	}
        	else{
        		
        		doc = docBuilder.parse(file);
        		
        	}

			// Create parent element
    		Element event = doc.createElement("event");

    		// create child node with attribute
    		Attr attr = doc.createAttribute("name");
    		
    		// set attribute value
    		attr.setValue(indName);
    		
    		// add attribute node to event 
    		event.setAttributeNode(attr);
    		
    		// Add new event element to root element
    		if (isNewFile){
    		
    			
    			rootElement.appendChild(event);  
    			
    		}
    		else{
    			
    			System.out.println(doc.getDocumentElement());
    			
    			rootElement = doc.getDocumentElement();
    			rootElement.appendChild(event);
    		}
    		
    		Iterator<Entry<String, String>> it = eventMap.entrySet().iterator();
 
    		Map.Entry<String, String> val;

    		while (it.hasNext()){
    			
    			System.out.println("Inside iterator");
    			
    			
    			val = (Entry<String, String>) it.next();
    			
           		// Create child
        		Element indType = doc.createElement(val.getKey());

           		// set value of child
        		indType.appendChild(doc.createTextNode(val.getValue()));
        		
        		// Add new child to element
        		event.appendChild(indType);

    		}
    		
    		System.out.println("Transforming");
    		// write the content into xml file
    		TransformerFactory transformerFactory = TransformerFactory.newInstance();
    		Transformer transformer = transformerFactory.newTransformer();
    		DOMSource source = new DOMSource(doc);
    		StreamResult result = new StreamResult(file);
    		
    		System.out.println("before transform source = "+source+" result = "+result);
    		transformer.transform(source, result);
    		System.out.println("after transform");
        	
        	
        } catch ( IOException | TransformerException e ) {
        	
           e.printStackTrace();
           
        } catch (SAXException e) {
			
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			
			e.printStackTrace();
		}
        
	} // End WriteResult
	
	/*
	 * Accept an input label
	 * check label exists in properties file.
	 * Count number of expected parameters
	 */
	boolean validateIndName(String indName){
		System.out.println("Validating indicator name");
		boolean isValid= false;
		Properties properties = loadIndProperty("indicators.properties");
		String value = properties.getProperty(indName);
			
		if (value != null){
			System.out.println("** Indicator exists **");
			isValid = true;
		}
		else
		{
			System.out.println("** Indicator doenst exist **");
		
		}
		return isValid;
	}
	
	
	public Map<String, String> getEventsMap(String indName, String indValue){
		//System.out.println("Please enter indicator value");
		//String indVal = null;
		
		// Console will wait for user input
		//Scanner userInput = new Scanner(System.in);
		
		// get user input
		//String indicator = userInput.next();
		
		//System.out.println("Thank you!");	
		
		boolean isValid = validateIndName(indName);
		Map <String,String>eventVals = new HashMap<String,String>();
		if (isValid){
			eventVals.put("val", indName);
			//System.out.println("Now Enter values for "+indicator);
			//indVal = userInput.next();
		}
		
		String [] inputValueList;
		Properties properties = loadIndProperty("indicators.properties");
		String prop = properties.getProperty(indName);
		
		// Get the indValue labels from property file and put them into an array
		String [] valueLabelList = prop.split(",");

		//Get user input and put into an array
		inputValueList = indValue.split(",");
		if (inputValueList.length != valueLabelList.length){
			System.out.println("The number of values do not match");
			isValid = false;
		}

		for (int i = 0; i < valueLabelList.length;i++ ){
			
			eventVals.put(valueLabelList[i], inputValueList[i]);
		
			System.out.println("valueLabelList["+i+"] = "+valueLabelList[i]);
			System.out.println("inputValueList["+i+"] = "+inputValueList[i]);
		}
				
		return eventVals;
	}
	
	//load indicator properties
	Properties loadIndProperty(String filename){
		
		// Create new properties object
		Properties properties = new Properties();
		
		// input stream
		FileInputStream inputStream;
		try {
			
			//load property file contents into input stream
			inputStream = new FileInputStream(filename);					
			properties.load(inputStream);

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return properties;
	}

	/*
	 * Accepts a filename as a string and returns the DOM object
	 */
	public Document readResult(String filename){
		File file = new File(localrepo,"filename");
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db;
		Document doc = null;
		try {
			
			db = dbf.newDocumentBuilder();
			doc = db.parse(file);
			doc.getDocumentElement().normalize();
			
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return doc;
	}//End method
	
}//End Class
